//
//  YYRunTimePerson.m
//  Pthread
//
//  Created by Yanyan Jiang on 2023/3/14.
//  Copyright © 2023 Yanyan Jiang. All rights reserved.
//

#import "YYRunTimePerson.h"
#import "YYRunTimeCat.h"
#import <objc/runtime.h>


@implementation YYRunTimePerson

//提醒编译器不要自动生成setter和getter的实现，不要自动生成成员变量
//@dynamic age;

//这种类型是没有公开的
struct method_t{
    SEL sel;
    char *types;
    IMP imp;
};


//- (void)test{
//    NSLog(@"%s",__func__);
//}


- (void)other{
    NSLog(@"%s",__func__);
}


void c_other(id self, SEL _cmd){
    NSLog(@"c_other -%@ -%@",self,NSStringFromSelector(_cmd));
}


+ (void)otherTestCls{
    NSLog(@"%s",__func__);
}


//动态解析调用C语言方法
//+ (BOOL)resolveInstanceMethod:(SEL)sel{
//    if(sel == @selector(test)){
//        class_addMethod(self, sel, (IMP)c_other, "v16@0:8");
//    }
//    return YES;
//    return [super resolveInstanceMethod:sel];
//}


//动态解析 返回yes 或者no 都可以
//+ (BOOL)resolveInstanceMethod:(SEL)sel{
//    if (sel == @selector(test)) {
//        Method method = class_getInstanceMethod(self, @selector(other));
//        class_addMethod(self, sel, method_getImplementation(method), method_getTypeEncoding(method));
//        return YES;
//    }
//    return [super resolveInstanceMethod:sel];
//}


//动态解析实例方法
//+ (BOOL)resolveInstanceMethod:(SEL)sel{
//    NSLog(@"%s",__func__);
//    if (sel == @selector(test)) {
//        struct method_t *otherMethod = (struct method_t*)class_getInstanceMethod(self, @selector(other));
//        class_addMethod(self, sel, otherMethod->imp, otherMethod->types);
//        //NSLog(@"%s,%p,%s",otherMethod->sel,otherMethod->imp,otherMethod->types);
//        return YES;
//    }
//    return [super resolveInstanceMethod:sel];
//}


//如果这个类没有这个方法并且动态解析也没有添加访求,说明这个类是没有能力处理这个方法的,需要转发给别人处理
//+ (BOOL)resolveInstanceMethod:(SEL)sel{
//    if(sel == @selector(forwardingTest)){
//
//        return YES;
//    }
//    return [super resolveInstanceMethod:sel];
//}


//消息转发给别人处理,这个方法有加号方法减号方法
//消息转发是不开源的，需要懂逆向才能看的懂
- (id)forwardingTargetForSelector:(SEL)aSelector{
    NSLog(@"%s",__FUNCTION__);
    if(aSelector == @selector(forwardingTest)){
        //return [[YYRunTimeCat alloc] init];
        //如果返回为空会调用方法签名方法
        //methodSignatureForSelector:
        return nil;
    }else if (aSelector == @selector(forwardingArgumentTest:)){
        return nil;
    }
    return [super forwardingTargetForSelector:aSelector];
}



//方法签名：返回值类型，参数类型
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector{
    if(aSelector == @selector(forwardingTest)){
        //如果返回的方法签名是有值的，会调用forwardInvocation:
        //把返回的方法签名封装到NSInvocation中
        return [NSMethodSignature signatureWithObjCTypes:"v16@0:8"];
        //return [NSMethodSignature signatureWithObjCTypes:"v@:"];
    }else if (aSelector == @selector(forwardingArgumentTest:)){
        return [NSMethodSignature signatureWithObjCTypes:"i16@0:8i16"];
        //让cat对象生成方法对应的方法签名，它是能生成的
        //return [ [[YYRunTimeCat alloc] init] methodSignatureForSelector:aSelector];
    }
    return [super methodSignatureForSelector:aSelector];
}


//在这个方法里可以处理你想处理的逻辑
//NSInvocation封装了一个方法调用，包括：方法调用者、方法名、方法参数
//anInvocation.target 方法调用者
//anInvocation.selector 方法名
//[anInvocation getArgument:NULL atIndex:0];
//你在这里想干什么就干什么
- (void)forwardInvocation:(NSInvocation *)anInvocation{
    //anInvocation.target = [[YYRunTimeCat alloc] init];
    //[anInvocation invoke]; //会报错
    
    //[anInvocation invokeWithTarget:[[YYRunTimeCat alloc] init]];
    int age;
    [anInvocation getArgument:&age atIndex:2];
    NSLog(@"age is %d",age+3);
    
    
    [anInvocation invokeWithTarget:[[YYRunTimeCat alloc] init]];
    int ret;
    [anInvocation getReturnValue:&ret];
    NSLog(@"ret is %d",ret);
    
}




//动态解决类方法
//+ (BOOL)resolveClassMethod:(SEL)sel{
//    if(sel == @selector(testCls)){
//        Method method = class_getClassMethod(object_getClass([YYRunTimePerson class]), @selector(otherTestCls));
//        class_addMethod(object_getClass([YYRunTimePerson class]), sel, method_getImplementation(method), method_getTypeEncoding(method));
//        return YES;
//    }
//    return [super resolveClassMethod:sel];
//}



+ (id)forwardingTargetForSelector:(SEL)aSelector{
    if(aSelector == @selector(testCls)) return [YYRunTimeCat class];
    return [super forwardingTargetForSelector:aSelector];
}


+ (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector{
    if(aSelector == @selector(testCls)) return [NSMethodSignature signatureWithObjCTypes:"v@:i"];
    return [super methodSignatureForSelector:aSelector];
}

+ (void)forwardInvocation:(NSInvocation *)anInvocation{
    [anInvocation invokeWithTarget:[YYRunTimeCat class]];
}


- (void)doesNotRecognizeSelector:(SEL)aSelector{
    NSLog(@"%s",__func__);
    
}

@end
